home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 2: Applications / Linux Cubed Series 2 - Applications.iso / editors / emacs / xemacs / xemacs-1.004 / xemacs-1 / xemacs-19.13 / lwlib / lwlib-Xm.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-06-21  |  55.1 KB  |  1,972 lines

  1. /* The lwlib interface to Motif widgets.
  2.    Copyright (C) 1992, 1993, 1994 Lucid, Inc.
  3.    Copyright (C) 1995 Tinker Systems and INS Engineering Corp.
  4.  
  5. This file is part of the Lucid Widget Library.
  6.  
  7. The Lucid Widget Library is free software; you can redistribute it and/or 
  8. modify it under the terms of the GNU General Public License as published by
  9. the Free Software Foundation; either version 2, or (at your option)
  10. any later version.
  11.  
  12. The Lucid Widget Library is distributed in the hope that it will be useful,
  13. but WITHOUT ANY WARRANTY; without even the implied warranty of 
  14. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15. GNU General Public License for more details.
  16.  
  17. You should have received a copy of the GNU General Public License
  18. along with GNU Emacs; see the file COPYING.  If not, write to
  19. the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
  20.  
  21. #include <stdlib.h>
  22. #include <unistd.h>
  23. #include <string.h>
  24. #include <stdio.h>
  25. #include <limits.h>
  26.  
  27. #include <X11/StringDefs.h>
  28. #include <X11/IntrinsicP.h>
  29. #include <X11/ObjectP.h>
  30. #include <X11/CoreP.h>
  31. #include <X11/CompositeP.h>
  32.  
  33. #include "lwlib-Xm.h"
  34. #include "lwlib-utils.h"
  35.  
  36. #include <Xm/Xm.h>
  37. #include <Xm/BulletinB.h>
  38. #include <Xm/CascadeB.h>
  39. #include <Xm/DrawingA.h>
  40. #include <Xm/FileSB.h>
  41. #include <Xm/Label.h>
  42. #include <Xm/List.h>
  43. #include <Xm/MenuShell.h>
  44. #include <Xm/MessageB.h>
  45. #include <Xm/PushB.h>
  46. #include <Xm/PushBG.h>
  47. #include <Xm/ArrowB.h>
  48. #include <Xm/ScrollBar.h>
  49. #include <Xm/SelectioB.h>
  50. #include <Xm/Text.h>
  51. #include <Xm/TextF.h>
  52. #include <Xm/ToggleB.h>
  53. #include <Xm/ToggleBG.h>
  54. #include <Xm/RowColumn.h>
  55. #include <Xm/ScrolledW.h>
  56. #include <Xm/Separator.h>
  57. #include <Xm/DialogS.h>
  58. #include <Xm/Form.h>
  59.  
  60. static void xm_pull_down_callback (Widget, XtPointer, XtPointer);
  61. static void xm_internal_update_other_instances (Widget, XtPointer,
  62.                         XtPointer);
  63. static void xm_generic_callback (Widget, XtPointer, XtPointer);
  64. static void xm_nosel_callback (Widget, XtPointer, XtPointer);
  65. #ifdef SCROLLBARS_MOTIF
  66. static void xm_scrollbar_callback (Widget, XtPointer, XtPointer);
  67. #endif
  68. #if 0
  69. static void xm_pop_down_callback (Widget, XtPointer, XtPointer);
  70. #endif /* 0 */
  71.  
  72. static void
  73. xm_update_menu (widget_instance* instance, Widget widget, widget_value* val,
  74.         Boolean deep_p);
  75.  
  76. /* Structures to keep destroyed instances */
  77. typedef struct _destroyed_instance 
  78. {
  79.   char*        name;
  80.   char*        type;
  81.   Widget     widget;
  82.   Widget    parent;
  83.   Boolean    pop_up_p;
  84.   struct _destroyed_instance*    next;
  85. } destroyed_instance;
  86.  
  87. static destroyed_instance*
  88. all_destroyed_instances = NULL;
  89.  
  90. /* Utility function. */
  91. static char *
  92. safe_strdup (char* s)
  93. {
  94.   char *result;
  95.   if (! s) return 0;
  96.   result = (char *) malloc (strlen (s) + 1);
  97.   if (! result)
  98.     return 0;
  99.   strcpy (result, s);
  100.   return result;
  101. }
  102.  
  103. static destroyed_instance*
  104. make_destroyed_instance (char* name, char* type, Widget widget, Widget parent,
  105.              Boolean pop_up_p)
  106. {
  107.   destroyed_instance* instance =
  108.     (destroyed_instance*)malloc (sizeof (destroyed_instance));
  109.   instance->name = safe_strdup (name);
  110.   instance->type = safe_strdup (type);
  111.   instance->widget = widget;
  112.   instance->parent = parent;
  113.   instance->pop_up_p = pop_up_p;
  114.   instance->next = NULL;
  115.   return instance;
  116. }
  117.              
  118. static void
  119. free_destroyed_instance (destroyed_instance* instance)
  120. {
  121.   free (instance->name);
  122.   free (instance->type);
  123.   free (instance);
  124. }
  125.  
  126. /* motif utility functions */
  127. Widget
  128. first_child (Widget widget)
  129. {
  130.   return ((CompositeWidget)widget)->composite.children [0];
  131. }
  132.  
  133. Boolean
  134. lw_motif_widget_p (Widget widget)
  135. {
  136.   return 
  137.     XtClass (widget) == xmDialogShellWidgetClass
  138.       || XmIsPrimitive (widget) || XmIsManager (widget) || XmIsGadget (widget);
  139. }
  140.  
  141. static char *
  142. resource_string (Widget widget, char *name)
  143. {
  144.   XtResource resource;
  145.   char *result = NULL;
  146.   
  147.   resource.resource_name = "labelString";
  148.   resource.resource_class = "LabelString"; /* #### should be Xmsomething... */
  149.   resource.resource_type = XtRString;
  150.   resource.resource_size = sizeof (String);
  151.   resource.resource_offset = 0;
  152.   resource.default_type = XtRImmediate;
  153.   resource.default_addr = 0;
  154.  
  155.   XtGetSubresources (widget, (XtPointer)&result, name,
  156.              name, &resource, 1, NULL, 0);
  157.   return result;
  158. }
  159.  
  160. static void
  161. destroy_all_children (Widget widget)
  162. {
  163.   Widget* children;
  164.   unsigned int number;
  165.   int i;
  166.  
  167.   children = XtCompositeChildren (widget, &number);
  168.   if (children)
  169.     {
  170.       /* Unmanage all children and destroy them.  They will only be 
  171.        * really destroyed when we get out of DispatchEvent. */
  172.       for (i = 0; i < number; i++)
  173.     {
  174.       Widget child = children [i];
  175.       if (!child->core.being_destroyed)
  176.         {
  177.           XtUnmanageChild (child);
  178.           XtDestroyWidget (child);
  179.         }
  180.     }
  181.       XtFree ((char *) children);
  182.     }
  183. }
  184.  
  185.  
  186.  
  187. static Boolean
  188. is_in_dialog_box (Widget w)
  189. {
  190.   Widget wmshell;
  191.  
  192.   wmshell = XtParent (w);
  193.   while (wmshell && (XtClass (wmshell) != xmDialogShellWidgetClass))
  194.     wmshell = XtParent (wmshell);
  195.  
  196.   if (wmshell && XtClass (wmshell) == xmDialogShellWidgetClass)
  197.     return True;
  198.   else
  199.     return False;
  200. }
  201.  
  202.  
  203. /* update the label of anything subclass of a label */
  204. static void
  205. xm_update_label (widget_instance* instance, Widget widget, widget_value* val)
  206. {
  207.   XmString built_string = 0;
  208.   XmString key_string = 0;
  209.   XmString val_string = 0;
  210.   XmString name_string = 0;
  211.   Arg al [256];
  212.   int ac;
  213.   
  214.   ac = 0;
  215.  
  216.   if (val->value)
  217.     {
  218.       /*
  219.        * Sigh.  The main text of a label is the name field for menubar
  220.        * entries.  The value field is a possible additional field to be
  221.        * contatenated on to the name field.  HOWEVER, with dialog boxes
  222.        * the value field is the complete text which is supposed to be
  223.        * displayed as the label.  Yuck.
  224.        */
  225.       if (is_in_dialog_box (widget))
  226.     {
  227.       char *value_name = NULL;
  228.  
  229.       value_name = resource_string (widget, val->value);
  230.       if (!value_name)
  231.         value_name = val->value;
  232.  
  233.       built_string =
  234.         XmStringCreateLtoR (value_name, XmSTRING_DEFAULT_CHARSET);
  235.     }
  236.       else
  237.     {
  238.       char *value_name = NULL;
  239.       char *res_name = NULL;
  240.  
  241.       res_name = resource_string (widget, val->name);
  242.       if (!res_name)
  243.         res_name = val->name;
  244.  
  245.       name_string =
  246.         XmStringCreateLtoR (res_name, XmSTRING_DEFAULT_CHARSET);
  247.  
  248.       value_name = XtMalloc (strlen (val->value) + 2);
  249.       *value_name = 0;
  250.       strcat (value_name, " ");
  251.       strcat (value_name, val->value);
  252.  
  253.       val_string =
  254.         XmStringCreateLtoR (value_name, XmSTRING_DEFAULT_CHARSET);
  255.  
  256.       built_string =
  257.         XmStringConcat (name_string, val_string);
  258.  
  259.       XtFree (value_name);
  260.     }
  261.  
  262.       XtSetArg (al [ac], XmNlabelString, built_string); ac++;
  263.       XtSetArg (al [ac], XmNlabelType, XmSTRING); ac++;
  264.     }
  265.   
  266.   if (val->key)
  267.     {
  268.       key_string = XmStringCreateLtoR (val->key, XmSTRING_DEFAULT_CHARSET);
  269.       XtSetArg (al [ac], XmNacceleratorText, key_string); ac++;
  270.     }
  271.  
  272.   if (ac)
  273.     XtSetValues (widget, al, ac);
  274.  
  275.   if (built_string)
  276.     XmStringFree (built_string);
  277.  
  278.   if (key_string)
  279.     XmStringFree (key_string);
  280.  
  281.   if (name_string)
  282.     XmStringFree (name_string);
  283. }
  284.  
  285. /* update of list */
  286. static void
  287. xm_update_list (widget_instance* instance, Widget widget, widget_value* val)
  288. {
  289.   widget_value* cur;
  290.   int i;
  291.   XtRemoveAllCallbacks (widget, XmNsingleSelectionCallback);
  292.   XtAddCallback (widget, XmNsingleSelectionCallback, xm_generic_callback,
  293.          instance);
  294.   for (cur = val->contents, i = 0; cur; cur = cur->next)
  295.     if (cur->value)
  296.       {
  297.     XmString xmstr = XmStringCreate (cur->value, XmSTRING_DEFAULT_CHARSET);
  298.     i += 1;
  299.     XmListAddItem (widget, xmstr, 0);
  300.     if (cur->selected)
  301.       XmListSelectPos (widget, i, False);
  302.     XmStringFree (xmstr);
  303.       }
  304. }
  305.  
  306. /* update of buttons */
  307. static void
  308. xm_update_pushbutton (widget_instance* instance, Widget widget,
  309.               widget_value* val)
  310. {
  311.   XtVaSetValues (widget, XmNalignment, XmALIGNMENT_CENTER, 0);
  312.   XtRemoveAllCallbacks (widget, XmNactivateCallback);
  313.   XtAddCallback (widget, XmNactivateCallback, xm_generic_callback, instance);
  314. }
  315.  
  316. static void
  317. xm_update_cascadebutton (widget_instance* instance, Widget widget,
  318.              widget_value* val)
  319. {
  320.   /* Should also rebuild the menu by calling ...update_menu... */
  321.   if (val
  322.       && val->type == CASCADE_TYPE
  323.       && val->contents
  324.       && val->contents->type == INCREMENTAL_TYPE)
  325.     {
  326.       /* okay, we're now doing a lisp callback to incrementally generate
  327.      more of the menu. */
  328.       XtRemoveAllCallbacks (widget, XmNcascadingCallback);
  329.       XtAddCallback (widget, XmNcascadingCallback, xm_pull_down_callback,
  330.              instance);
  331.       XtCallCallbacks ((Widget)widget,
  332.               XmNcascadingCallback,
  333.               (XtPointer)val->contents);
  334.  
  335.     } else {
  336.       XtRemoveAllCallbacks (widget, XmNcascadingCallback);
  337.       XtAddCallback (widget, XmNcascadingCallback, xm_pull_down_callback,
  338.              instance);
  339.     }      
  340. }
  341.  
  342. /* update toggle and radiobox */
  343. static void
  344. xm_update_toggle (widget_instance* instance, Widget widget, widget_value* val)
  345. {
  346.   XtRemoveAllCallbacks (widget, XmNvalueChangedCallback);
  347. #ifndef ENERGIZE
  348.   XtAddCallback (widget, XmNvalueChangedCallback, xm_generic_callback,
  349.          instance);
  350. #else
  351.  XtAddCallback (widget, XmNvalueChangedCallback,
  352.                 xm_internal_update_other_instances, instance);
  353. #endif 
  354.   XtVaSetValues (widget, XmNset, val->selected,
  355.          XmNalignment, XmALIGNMENT_BEGINNING, 0);
  356. }
  357.  
  358. static void
  359. xm_update_radiobox (widget_instance* instance, Widget widget,
  360.             widget_value* val)
  361. {
  362.   Widget toggle;
  363.   widget_value* cur;
  364.  
  365.   /* update the callback */
  366.   XtRemoveAllCallbacks (widget, XmNentryCallback);
  367.   XtAddCallback (widget, XmNentryCallback, xm_generic_callback, instance);
  368.  
  369.   /* first update all the toggles */
  370.   /* Energize kernel interface is currently bad.  It sets the selected widget
  371.      with the selected flag but returns it by its name.  So we currently
  372.      have to support both setting the selection with the selected slot
  373.      of val contents and setting it with the "value" slot of val.  The latter
  374.      has a higher priority.  This to be removed when the kernel is fixed. */
  375.   for (cur = val->contents; cur; cur = cur->next)
  376.     {
  377.       toggle = XtNameToWidget (widget, cur->value);
  378.       if (toggle)
  379.     {
  380.       XtVaSetValues (toggle, XmNsensitive, cur->enabled, 0);
  381.       if (!val->value && cur->selected)
  382.         XtVaSetValues (toggle, XmNset, cur->selected, 0);
  383.       if (val->value && strcmp (val->value, cur->value))
  384.         XtVaSetValues (toggle, XmNset, False, 0);
  385.     }
  386.     }
  387.  
  388.   /* The selected was specified by the value slot */
  389.   if (val->value)
  390.     {
  391.       toggle = XtNameToWidget (widget, val->value);
  392.       if (toggle)
  393.     XtVaSetValues (toggle, XmNset, True, 0);
  394.     }
  395. }
  396.  
  397. /* update a popup menu, pulldown menu or a menubar */
  398. static void
  399. make_menu_in_widget (widget_instance* instance, Widget widget,
  400.              widget_value* val)
  401. {
  402.   Widget* children = 0;
  403.   int num_children;
  404.   int child_index;
  405.   widget_value* cur;
  406.   Widget button = 0;
  407.   Widget menu;
  408.   Arg al [256];
  409.   int ac;
  410.   Boolean menubar_p;
  411.  
  412.   /* Allocate the children array */
  413.   for (num_children = 0, cur = val; cur; num_children++, cur = cur->next);
  414.   children = (Widget*)XtMalloc (num_children * sizeof (Widget));
  415.  
  416.   /* tricky way to know if this RowColumn is a menubar or a pulldown... */
  417.   menubar_p = False;
  418.   XtVaGetValues (widget, XmNisHomogeneous, &menubar_p, NULL);
  419.  
  420.   /* add the unmap callback for popups and pulldowns */
  421.   /*** this sounds bogus ***/
  422.   /* probably because it is -- cet */
  423. /*
  424.   if (!menubar_p)
  425.     XtAddCallback (XtParent (widget), XmNpopdownCallback,
  426.            xm_pop_down_callback, (XtPointer)instance);
  427. */
  428.  
  429.   num_children = 0;
  430.   for (child_index = 0, cur = val; cur; child_index++, cur = cur->next)
  431.     {    
  432.       ac = 0;
  433.       button = 0;
  434.       XtSetArg (al [ac], XmNsensitive, cur->enabled); ac++;
  435.       XtSetArg (al [ac], XmNalignment, XmALIGNMENT_BEGINNING); ac++;
  436.       XtSetArg (al [ac], XmNuserData, cur->call_data); ac++;
  437.  
  438.       switch (cur->type)
  439.     {
  440.     case PUSHRIGHT_TYPE:
  441.       /* A pushright marker which is not needed for the real Motif
  442.              menubar. */
  443.       break;
  444.     case SEPARATOR_TYPE:
  445.       ac = 0;
  446.       if (cur->value)
  447.         {
  448.           /* #### - xlwmenu.h supports several types that motif does
  449.          not.  Also, motif supports pixmaps w/ type NO_LINE and
  450.          lwlib provides no way to access that functionality. --Stig */
  451.           XtSetArg (al [ac], XmNseparatorType, cur->value), ac++;
  452.         }
  453.       button = XmCreateSeparator (widget, "separator", al, ac);
  454.       break;
  455.     case CASCADE_TYPE:
  456.       menu = XmCreatePulldownMenu (widget, "pulldown", NULL, 0);
  457.       make_menu_in_widget (instance, menu, cur->contents);
  458.       XtSetArg (al [ac], XmNsubMenuId, menu); ac++;
  459.       button = XmCreateCascadeButton (widget, cur->name, al, ac);
  460.  
  461.       xm_update_label (instance, button, cur);
  462.  
  463.       XtAddCallback (button, XmNcascadingCallback, xm_pull_down_callback,
  464.              (XtPointer)instance);
  465.       break;
  466.     default:
  467.       if (menubar_p)
  468.         button = XmCreateCascadeButton (widget, cur->name, al, ac);
  469.       else if (!cur->call_data)
  470.         button = XmCreateLabel (widget, cur->name, al, ac);
  471.       else if (cur->type == TOGGLE_TYPE || cur->type == RADIO_TYPE)
  472.         {
  473.           if (cur->type == TOGGLE_TYPE)
  474.         {
  475.           XtSetArg (al [ac], XmNindicatorType, XmN_OF_MANY); ac++;
  476.         }
  477.           else
  478.         {
  479.           XtSetArg (al [ac], XmNindicatorType, XmONE_OF_MANY); ac++;
  480.         }
  481.           
  482.           XtSetArg (al [ac], XmNvisibleWhenOff, True); ac++;
  483.           button = XmCreateToggleButtonGadget (widget, cur->name, al, ac);
  484.         }
  485.       else
  486.         button = XmCreatePushButtonGadget (widget, cur->name, al, ac);
  487.  
  488.       xm_update_label (instance, button, cur);
  489.  
  490.       /* don't add a callback to a simple label */
  491.       if (cur->type == TOGGLE_TYPE || cur->type == RADIO_TYPE)
  492.         xm_update_toggle (instance, button, cur);
  493.       else if (cur->call_data)
  494.         XtAddCallback (button, XmNactivateCallback, xm_generic_callback,
  495.                (XtPointer)instance);
  496.     } /* switch (cur->type) */
  497.  
  498.       if (button)
  499.     children [num_children++] = button;
  500.     }
  501.  
  502.   /* Last entry is the help button.  This used be done after managing
  503.      the buttons.  The comment claimed that it had to be done this way
  504.      otherwise the menubar ended up only 4 pixels high.  That must
  505.      have been in the Old World.  In the New World it stays the proper
  506.      height if you don't manage them until after you set this and as a
  507.      bonus the Help menu ends up where it is supposed to. */
  508.   if (button)
  509.     {
  510.       ac = 0;
  511.       XtSetArg (al [ac], XmNmenuHelpWidget, button); ac++;
  512.       XtSetValues (widget, al, ac);
  513.     }
  514.  
  515.   if (num_children)
  516.     XtManageChildren (children, num_children);
  517.  
  518.   XtFree ((char *) children);
  519. }
  520.  
  521. static void
  522. update_one_menu_entry (widget_instance* instance, Widget widget,
  523.                widget_value* val, Boolean deep_p)
  524. {
  525.   Arg al [256];
  526.   int ac;
  527.   Widget menu;
  528.   widget_value* contents;
  529.  
  530.   if (val->change == NO_CHANGE)
  531.     return;
  532.  
  533.   /* update the sensitivity and userdata */
  534.   /* Common to all widget types */
  535.   XtVaSetValues (widget,
  536.          XmNsensitive, val->enabled,
  537.          XmNuserData, val->call_data,
  538.          0);
  539.  
  540.   /* update the menu button as a label. */
  541.   if (val->change >= VISIBLE_CHANGE)
  542.     {
  543.       xm_update_label (instance, widget, val);
  544.       if (XtClass (widget) == xmToggleButtonWidgetClass
  545.       || XtClass (widget) == xmToggleButtonGadgetClass)
  546.     {
  547.       xm_update_toggle (instance, widget, val);
  548.     }
  549.     }
  550.  
  551.  
  552.   /* update the pulldown/pullaside as needed */
  553.   menu = NULL;
  554.   XtVaGetValues (widget, XmNsubMenuId, &menu, NULL);
  555.   
  556.   contents = val->contents;
  557.  
  558.   if (!menu)
  559.     {
  560.       if (contents)
  561.     {
  562.       menu = XmCreatePulldownMenu (widget, "pulldown", NULL, 0);
  563.       make_menu_in_widget (instance, menu, contents);
  564.       ac = 0;
  565.       XtSetArg (al [ac], XmNsubMenuId, menu); ac++;
  566.       XtSetValues (widget, al, ac);
  567.     }
  568.     }
  569.   else if (!contents)
  570.     {
  571.       ac = 0;
  572.       XtSetArg (al [ac], XmNsubMenuId, NULL); ac++;
  573.       XtSetValues (widget, al, ac);
  574.       XtDestroyWidget (menu);
  575.     }
  576.   else if (deep_p && contents->change != NO_CHANGE)
  577.     xm_update_menu (instance, menu, val, 1);
  578. }
  579.  
  580. static void
  581. xm_update_menu (widget_instance* instance, Widget widget, widget_value* val,
  582.         Boolean deep_p)
  583. {
  584.   /* Widget is a RowColumn widget whose contents have to be updated
  585.    * to reflect the list of items in val->contents */
  586.   if (val->contents->change == STRUCTURAL_CHANGE)
  587.     {
  588.       destroy_all_children (widget);
  589.       make_menu_in_widget (instance, widget, val->contents);
  590.     }
  591.   else
  592.     {
  593.       /* Update all the buttons of the RowColumn in order. */
  594.       Widget* children;
  595.       unsigned int num_children;
  596.       int i;
  597.       widget_value *cur = 0;
  598.  
  599.       children = XtCompositeChildren (widget, &num_children);
  600.       if (children)
  601.     {
  602.       for (i = 0, cur = val->contents; i < num_children; i++)
  603.         {
  604.           if (!cur)
  605.         abort ();
  606.           /* skip if this is a pushright marker or a separator */
  607.           if (cur->type == PUSHRIGHT_TYPE || cur->type == SEPARATOR_TYPE)
  608.         {
  609.           cur = cur->next;
  610. #if 0
  611.           /* #### - this could puke if you have a separator as the
  612.              last item on a pullright menu. */
  613.           if (!cur)
  614.             abort ();
  615. #else
  616.           if (!cur)
  617.             continue;
  618. #endif
  619.         }
  620.           if (children [i]->core.being_destroyed
  621.           || strcmp (XtName (children [i]), cur->name))
  622.         continue;
  623.           update_one_menu_entry (instance, children [i], cur, deep_p);
  624.           cur = cur->next;
  625.         }
  626.       XtFree ((char *) children);
  627.     }
  628.       if (cur)
  629.     abort ();
  630.     }
  631. }
  632.  
  633.  
  634. /* update text widgets */
  635.  
  636. static void
  637. xm_update_text (widget_instance* instance, Widget widget, widget_value* val)
  638. {
  639.   XmTextSetString (widget, val->value ? val->value : "");
  640.   XtRemoveAllCallbacks (widget, XmNactivateCallback);
  641.   XtAddCallback (widget, XmNactivateCallback, xm_generic_callback, instance);
  642.   XtRemoveAllCallbacks (widget, XmNvalueChangedCallback);
  643.   XtAddCallback (widget, XmNvalueChangedCallback,
  644.          xm_internal_update_other_instances, instance);
  645. }
  646.  
  647. static void
  648. xm_update_text_field (widget_instance* instance, Widget widget,
  649.               widget_value* val)
  650. {
  651.   XmTextFieldSetString (widget, val->value ? val->value : "");
  652.   XtRemoveAllCallbacks (widget, XmNactivateCallback);
  653.   XtAddCallback (widget, XmNactivateCallback, xm_generic_callback, instance);
  654.   XtRemoveAllCallbacks (widget, XmNvalueChangedCallback);
  655.   XtAddCallback (widget, XmNvalueChangedCallback,
  656.          xm_internal_update_other_instances, instance);
  657. }
  658.  
  659. /*
  660.  * If this function looks like it does a lot more work than it needs to,
  661.  * you're right.  Blame the Motif scrollbar for not being smart about
  662.  * updating its appearance.
  663.  */
  664. static void
  665. xm_update_scrollbar (widget_instance *instance, Widget widget,
  666.              widget_value *val)
  667. {
  668.   if (val->scrollbar_data)
  669.     {
  670.       scrollbar_values *data = val->scrollbar_data;
  671.       int widget_sliderSize, widget_val;
  672.       int new_sliderSize, new_value;
  673.       double percent;
  674.       double h_water, l_water;
  675.  
  676.       /*
  677.        * First size and position the scrollbar widget.
  678.        */
  679.       XtVaSetValues (widget,
  680.              XtNx, data->scrollbar_x,
  681.              XtNy, data->scrollbar_y,
  682.              XtNwidth, data->scrollbar_width,
  683.              XtNheight, data->scrollbar_height,
  684.              0);
  685.  
  686.       /*
  687.        * Now the size the scrollbar's slider.
  688.        */
  689.  
  690.       XtVaGetValues (widget,
  691.              XmNsliderSize, &widget_sliderSize,
  692.              XmNvalue, &widget_val,
  693.              0);
  694.  
  695.       percent = (double) data->slider_size /
  696.     (double) (data->maximum - data->minimum);
  697.       new_sliderSize = (int) ((double) (INT_MAX - 1) * percent);
  698.  
  699.       percent = (double) (data->slider_position - data->minimum) /
  700.     (double) (data->maximum - data->minimum);
  701.       new_value = (int) ((double) (INT_MAX - 1) * percent);
  702.  
  703.       if (new_sliderSize > (INT_MAX - 1))
  704.     new_sliderSize = INT_MAX - 1;
  705.       if (new_sliderSize < 1)
  706.     new_sliderSize = 1;
  707.  
  708.       if (new_value > (INT_MAX - new_sliderSize))
  709.     new_value = INT_MAX - new_sliderSize;
  710.       else if (new_value < 1)
  711.     new_value = 1;
  712.  
  713.       h_water = 1.05;
  714.       l_water = 0.95;
  715.       if (new_sliderSize != widget_sliderSize || new_value != widget_val)
  716.     {
  717.       int force = ((INT_MAX - widget_sliderSize - widget_val)
  718.                ? 0
  719.                : (INT_MAX - new_sliderSize - new_value));
  720.  
  721.       if (force
  722.           || (double)new_sliderSize < (l_water * (double)widget_sliderSize)
  723.           || (double)new_sliderSize > (h_water * (double)widget_sliderSize)
  724.           || (double)new_value < (l_water * (double)widget_val)
  725.           || (double)new_value > (h_water * (double)widget_val))
  726.         {
  727.           XmScrollBarSetValues (widget, new_value, new_sliderSize, 1, 1,
  728.                     False);
  729.         }
  730.     }
  731.     }
  732. }
  733.  
  734.  
  735. /* update a motif widget */
  736.  
  737. void
  738. xm_update_one_widget (widget_instance* instance, Widget widget,
  739.               widget_value* val, Boolean deep_p)
  740. {
  741.   WidgetClass class;
  742.   
  743.   /* Mark as not edited */
  744.   val->edited = False;
  745.  
  746.   /* Common to all widget types */
  747.   XtVaSetValues (widget,
  748.          XmNsensitive, val->enabled,
  749.          XmNuserData, val->call_data,
  750.          0);
  751.   
  752.   /* Common to all label like widgets */
  753.   if (XtIsSubclass (widget, xmLabelWidgetClass))
  754.     xm_update_label (instance, widget, val);
  755.   
  756.   class = XtClass (widget);
  757.   /* Class specific things */
  758.   if (class == xmPushButtonWidgetClass ||
  759.       class == xmArrowButtonWidgetClass)
  760.     {
  761.       xm_update_pushbutton (instance, widget, val);
  762.     }
  763.   else if (class == xmCascadeButtonWidgetClass)
  764.     {
  765.       xm_update_cascadebutton (instance, widget, val);
  766.     }
  767.   else if (class == xmToggleButtonWidgetClass
  768.        || class == xmToggleButtonGadgetClass)
  769.     {
  770.       xm_update_toggle (instance, widget, val);
  771.     }
  772.   else if (class == xmRowColumnWidgetClass)
  773.     {
  774.       Boolean radiobox = 0;
  775.       
  776.       XtVaGetValues (widget, XmNradioBehavior, &radiobox, NULL);
  777.       
  778.       if (radiobox)
  779.     xm_update_radiobox (instance, widget, val);
  780.       else
  781.     xm_update_menu (instance, widget, val, deep_p);
  782.     }
  783.   else if (class == xmTextWidgetClass)
  784.     {
  785.       xm_update_text (instance, widget, val);
  786.     }
  787.   else if (class == xmTextFieldWidgetClass)
  788.     {
  789.       xm_update_text_field (instance, widget, val);
  790.     }
  791.   else if (class == xmListWidgetClass)
  792.     {
  793.       xm_update_list (instance, widget, val);
  794.     }
  795.   else if (class == xmScrollBarWidgetClass)
  796.     {
  797.       xm_update_scrollbar (instance, widget, val);
  798.     }
  799. }
  800.  
  801. /* getting the value back */
  802. void
  803. xm_update_one_value (widget_instance* instance, Widget widget,
  804.              widget_value* val)
  805. {
  806.   WidgetClass class = XtClass (widget);
  807.   widget_value *old_wv;
  808.  
  809.   /* copy the call_data slot into the "return" widget_value */
  810.   for (old_wv = instance->info->val->contents; old_wv; old_wv = old_wv->next)
  811.     if (!strcmp (val->name, old_wv->name))
  812.       {
  813.     val->call_data = old_wv->call_data;
  814.     break;
  815.       }
  816.   
  817.   if (class == xmToggleButtonWidgetClass || class == xmToggleButtonGadgetClass)
  818.     {
  819.       XtVaGetValues (widget, XmNset, &val->selected, 0);
  820.       val->edited = True;
  821.     }
  822.   else if (class == xmTextWidgetClass)
  823.     {
  824.       if (val->value)
  825.     free (val->value);
  826.       val->value = XmTextGetString (widget);
  827.       val->edited = True;
  828.     }
  829.   else if (class == xmTextFieldWidgetClass)
  830.     {
  831.       if (val->value)
  832.     free (val->value);
  833.       val->value = XmTextFieldGetString (widget);
  834.       val->edited = True;
  835.     }
  836.   else if (class == xmRowColumnWidgetClass)
  837.     {
  838.       Boolean radiobox = 0;
  839.       
  840.       XtVaGetValues (widget, XmNradioBehavior, &radiobox, NULL);
  841.       
  842.       if (radiobox)
  843.     {
  844.       CompositeWidget radio = (CompositeWidget)widget;
  845.       int i;
  846.       for (i = 0; i < radio->composite.num_children; i++)
  847.         {
  848.           int set = False;
  849.           Widget toggle = radio->composite.children [i];
  850.           
  851.           XtVaGetValues (toggle, XmNset, &set, 0);
  852.           if (set)
  853.         {
  854.           if (val->value)
  855.             free (val->value);
  856.           val->value = safe_strdup (XtName (toggle));
  857.         }
  858.         }
  859.       val->edited = True;
  860.     }
  861.     }
  862.   else if (class == xmListWidgetClass)
  863.     {
  864.       int pos_cnt;
  865.       int* pos_list;
  866.       if (XmListGetSelectedPos (widget, &pos_list, &pos_cnt))
  867.     {
  868.       int i;
  869.       widget_value* cur;
  870.       for (cur = val->contents, i = 0; cur; cur = cur->next)
  871.         if (cur->value)
  872.           {
  873.         int j;
  874.         cur->selected = False;
  875.         i += 1;
  876.         for (j = 0; j < pos_cnt; j++)
  877.           if (pos_list [j] == i)
  878.             {
  879.               cur->selected = True;
  880.               val->value = safe_strdup (cur->name);
  881.             }
  882.           }
  883.       val->edited = 1;
  884.       XtFree ((char *) pos_list);
  885.     }
  886.     }
  887.   else if (class == xmScrollBarWidgetClass)
  888.     {
  889.       /* This function is not used by the scrollbar. */
  890.       return;
  891.     }
  892. }
  893.  
  894.  
  895. /* This function is for activating a button from a program.  It's wrong because
  896.    we pass a NULL argument in the call_data which is not Motif compatible.
  897.    This is used from the XmNdefaultAction callback of the List widgets to
  898.    have a dble-click put down a dialog box like the button woudl do. 
  899.    I could not find a way to do that with accelerators.
  900.  */
  901. static void
  902. activate_button (Widget widget, XtPointer closure, XtPointer call_data)
  903. {
  904.   Widget button = (Widget)closure;
  905.   XtCallCallbacks (button, XmNactivateCallback, NULL);
  906. }
  907.  
  908. /* creation functions */
  909.  
  910. /* dialogs */
  911.  
  912. #if (XmVersion >= 1002)
  913. # define ARMANDACTIVATE_KLUDGE
  914. # define DND_KLUDGE
  915. #endif
  916.  
  917. #ifdef ARMANDACTIVATE_KLUDGE
  918.  /* We want typing Return at a dialog box to select the default button; but
  919.     we're satisfied with having it select the leftmost button instead.
  920.  
  921.     In Motif 1.1.5 we could do this by putting this resource in the
  922.     app-defaults file:
  923.  
  924.     *dialog*button1.accelerators:#override\
  925.     <KeyPress>Return: ArmAndActivate()\n\
  926.     <KeyPress>KP_Enter: ArmAndActivate()\n\
  927.     Ctrl<KeyPress>m: ArmAndActivate()\n
  928.  
  929.     but that doesn't work with 1.2.1 and I don't understand why. However,
  930.     doing the equivalent C code does work, with the notable disadvantage that
  931.     the user can't override it.  So that's what we do until we figure out
  932.     something better....
  933.   */
  934. static char button_trans[] = "\
  935. <KeyPress>Return: ArmAndActivate()\n\
  936. <KeyPress>KP_Enter: ArmAndActivate()\n\
  937. Ctrl<KeyPress>m: ArmAndActivate()\n";
  938.  
  939. #endif /* ARMANDACTIVATE_KLUDGE */
  940.  
  941.  
  942. #ifdef DND_KLUDGE
  943.  /* This is a kludge to disable drag-and-drop in dialog boxes.  The symptom
  944.     was a segv down in libXm somewhere if you used the middle button on a
  945.     dialog box to begin a drag; when you released the button to make a drop
  946.     things would lose if you were not over the button where you started the 
  947.     drag (canceling the operation).  This was probably due to the fact that
  948.     the dialog boxes were not set up to handle a drag but were trying to do
  949.     so anyway for some reason.
  950.  
  951.     So we disable drag-and-drop in dialog boxes by turning off the binding for
  952.     Btn2Down which, by default, initiates a drag.  Clearly this is a shitty
  953.     solution as it only works in default configurations, but...
  954.   */
  955. static char disable_dnd_trans[] = "<Btn2Down>: ";
  956. #endif /* DND_KLUDGE */
  957.  
  958.  
  959. static Widget
  960. make_dialog (char* name, Widget parent, Boolean pop_up_p,
  961.          char* shell_title, char* icon_name, Boolean text_input_slot,
  962.          Boolean radio_box, Boolean list,
  963.          int left_buttons, int right_buttons)
  964. {
  965.   Widget result;
  966.   Widget form;
  967.   Widget row;
  968.   Widget icon;
  969.   Widget icon_separator;
  970.   Widget message;
  971.   Widget value = 0;
  972.   Widget separator;
  973.   Widget button = 0;
  974.   Widget children [16];        /* for the final XtManageChildren */
  975.   int    n_children;
  976.   Arg     al[64];            /* Arg List */
  977.   int     ac;            /* Arg Count */
  978.   int     i;
  979.   
  980. #ifdef DND_KLUDGE
  981.   XtTranslations dnd_override = XtParseTranslationTable (disable_dnd_trans);
  982. # define DO_DND_KLUDGE(widget) XtOverrideTranslations ((widget), dnd_override)
  983. #else  /* ! DND_KLUDGE */
  984. # define DO_DND_KLUDGE(widget)
  985. #endif /* ! DND_KLUDGE */
  986.  
  987.   if (pop_up_p)
  988.     {
  989.       ac = 0;
  990.       XtSetArg(al[ac], XmNtitle, shell_title); ac++;
  991.       XtSetArg(al[ac], XtNallowShellResize, True); ac++;
  992.       XtSetArg(al[ac], XmNdeleteResponse, XmUNMAP); ac++;
  993.       result = XmCreateDialogShell (parent, "dialog", al, ac);
  994.  
  995.       XtSetArg(al[ac], XmNautoUnmanage, FALSE); ac++;
  996. /*      XtSetArg(al[ac], XmNautoUnmanage, TRUE); ac++; */ /* ####is this ok? */
  997.       XtSetArg(al[ac], XmNnavigationType, XmTAB_GROUP); ac++;
  998.       form = XmCreateForm (result, shell_title, al, ac);
  999.     }
  1000.   else
  1001.     {
  1002.       ac = 0;
  1003.       XtSetArg(al[ac], XmNautoUnmanage, FALSE); ac++;
  1004.       XtSetArg(al[ac], XmNnavigationType, XmTAB_GROUP); ac++;
  1005.       form = XmCreateForm (parent, shell_title, al, ac);
  1006.       result = form;
  1007.     }
  1008.  
  1009.   ac = 0;
  1010.   XtSetArg(al[ac], XmNpacking, XmPACK_COLUMN); ac++;
  1011.   XtSetArg(al[ac], XmNorientation, XmVERTICAL); ac++;
  1012.   XtSetArg(al[ac], XmNnumColumns, left_buttons + right_buttons + 1); ac++;
  1013.   XtSetArg(al[ac], XmNmarginWidth, 0); ac++;
  1014.   XtSetArg(al[ac], XmNmarginHeight, 0); ac++;
  1015.   XtSetArg(al[ac], XmNspacing, 13); ac++;
  1016.   XtSetArg(al[ac], XmNadjustLast, False); ac++;
  1017.   XtSetArg(al[ac], XmNalignment, XmALIGNMENT_CENTER); ac++;
  1018.   XtSetArg(al[ac], XmNisAligned, True); ac++;
  1019.   XtSetArg(al[ac], XmNtopAttachment, XmATTACH_NONE); ac++;
  1020.   XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_FORM); ac++;
  1021.   XtSetArg(al[ac], XmNbottomOffset, 13); ac++;
  1022.   XtSetArg(al[ac], XmNleftAttachment, XmATTACH_FORM); ac++;
  1023.   XtSetArg(al[ac], XmNleftOffset, 13); ac++;
  1024.   XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
  1025.   XtSetArg(al[ac], XmNrightOffset, 13); ac++;
  1026.   row = XmCreateRowColumn (form, "row", al, ac);
  1027.   
  1028.   n_children = 0;
  1029.   for (i = 0; i < left_buttons; i++)
  1030.     {
  1031.       char button_name [16];
  1032.       sprintf (button_name, "button%d", i + 1);
  1033.       ac = 0;
  1034.       if (i == 0)
  1035.     {
  1036.       XtSetArg(al[ac], XmNhighlightThickness, 1); ac++;
  1037.       XtSetArg(al[ac], XmNshowAsDefault, TRUE); ac++;
  1038.     }
  1039.       XtSetArg(al[ac], XmNnavigationType, XmTAB_GROUP); ac++;
  1040.       children [n_children] = XmCreatePushButton (row, button_name, al, ac);
  1041.       DO_DND_KLUDGE (children [n_children]);
  1042.  
  1043.       if (i == 0)
  1044.     {
  1045.       button = children [n_children];
  1046.       ac = 0;
  1047.       XtSetArg(al[ac], XmNdefaultButton, button); ac++;
  1048.       XtSetValues (row, al, ac);
  1049.  
  1050. #ifdef ARMANDACTIVATE_KLUDGE    /* See comment above */
  1051.       {
  1052.         XtTranslations losers = XtParseTranslationTable (button_trans);
  1053.         XtOverrideTranslations (button, losers);
  1054.         XtFree ((char *) losers);
  1055.       }
  1056. #endif /* ARMANDACTIVATE_KLUDGE */
  1057.     }
  1058.  
  1059.       n_children++;
  1060.     }
  1061.  
  1062.   /* invisible seperator button */
  1063.   ac = 0;
  1064.   XtSetArg (al[ac], XmNmappedWhenManaged, FALSE); ac++;
  1065.   children [n_children] = XmCreateLabel (row, "separator_button", al, ac);
  1066.   DO_DND_KLUDGE (children [n_children]);
  1067.   n_children++;
  1068.   
  1069.   for (i = 0; i < right_buttons; i++)
  1070.     {
  1071.       char button_name [16];
  1072.       sprintf (button_name, "button%d", left_buttons + i + 1);
  1073.       ac = 0;
  1074.       XtSetArg(al[ac], XmNnavigationType, XmTAB_GROUP); ac++;
  1075.       children [n_children] = XmCreatePushButton (row, button_name, al, ac);
  1076.       DO_DND_KLUDGE (children [n_children]);
  1077.       if (! button) button = children [n_children];
  1078.       n_children++;
  1079.     }
  1080.   
  1081.   XtManageChildren (children, n_children);
  1082.   
  1083.   ac = 0;
  1084.   XtSetArg(al[ac], XmNtopAttachment, XmATTACH_NONE); ac++;
  1085.   XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_WIDGET); ac++;
  1086.   XtSetArg(al[ac], XmNbottomOffset, 13); ac++;
  1087.   XtSetArg(al[ac], XmNbottomWidget, row); ac++;
  1088.   XtSetArg(al[ac], XmNleftAttachment, XmATTACH_FORM); ac++;
  1089.   XtSetArg(al[ac], XmNleftOffset, 0); ac++;
  1090.   XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
  1091.   XtSetArg(al[ac], XmNrightOffset, 0); ac++;
  1092.   separator = XmCreateSeparator (form, "", al, ac);
  1093.  
  1094.   ac = 0;
  1095.   XtSetArg(al[ac], XmNlabelType, XmPIXMAP); ac++;
  1096.   XtSetArg(al[ac], XmNtopAttachment, XmATTACH_FORM); ac++;
  1097.   XtSetArg(al[ac], XmNtopOffset, 13); ac++;
  1098.   XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_NONE); ac++;
  1099.   XtSetArg(al[ac], XmNleftAttachment, XmATTACH_FORM); ac++;
  1100.   XtSetArg(al[ac], XmNleftOffset, 13); ac++;
  1101.   XtSetArg(al[ac], XmNrightAttachment, XmATTACH_NONE); ac++;
  1102.   icon = XmCreateLabel (form, icon_name, al, ac);
  1103.   DO_DND_KLUDGE (icon);
  1104.  
  1105.   ac = 0;
  1106.   XtSetArg(al[ac], XmNmappedWhenManaged, FALSE); ac++;
  1107.   XtSetArg(al[ac], XmNtopAttachment, XmATTACH_WIDGET); ac++;
  1108.   XtSetArg(al[ac], XmNtopOffset, 6); ac++;
  1109.   XtSetArg(al[ac], XmNtopWidget, icon); ac++;
  1110.   XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_WIDGET); ac++;
  1111.   XtSetArg(al[ac], XmNbottomOffset, 6); ac++;
  1112.   XtSetArg(al[ac], XmNbottomWidget, separator); ac++;
  1113.   XtSetArg(al[ac], XmNleftAttachment, XmATTACH_NONE); ac++;
  1114.   XtSetArg(al[ac], XmNrightAttachment, XmATTACH_NONE); ac++;
  1115.   icon_separator = XmCreateLabel (form, "", al, ac);
  1116.   DO_DND_KLUDGE (icon_separator);
  1117.  
  1118.   if (text_input_slot)
  1119.     {
  1120.       ac = 0;
  1121.       XtSetArg(al[ac], XmNcolumns, 50); ac++;
  1122.       XtSetArg(al[ac], XmNtopAttachment, XmATTACH_NONE); ac++;
  1123.       XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_WIDGET); ac++;
  1124.       XtSetArg(al[ac], XmNbottomOffset, 13); ac++;
  1125.       XtSetArg(al[ac], XmNbottomWidget, separator); ac++;
  1126.       XtSetArg(al[ac], XmNleftAttachment, XmATTACH_WIDGET); ac++;
  1127.       XtSetArg(al[ac], XmNleftOffset, 13); ac++;
  1128.       XtSetArg(al[ac], XmNleftWidget, icon); ac++;
  1129.       XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
  1130.       XtSetArg(al[ac], XmNrightOffset, 13); ac++;
  1131.       value = XmCreateTextField (form, "value", al, ac);
  1132.       DO_DND_KLUDGE (value);
  1133.     }
  1134.   else if (radio_box)
  1135.     {
  1136.       Widget radio_butt;
  1137.       ac = 0;
  1138.       XtSetArg(al[ac], XmNmarginWidth, 0); ac++;
  1139.       XtSetArg(al[ac], XmNmarginHeight, 0); ac++;
  1140.       XtSetArg(al[ac], XmNspacing, 13); ac++;
  1141.       XtSetArg(al[ac], XmNalignment, XmALIGNMENT_CENTER); ac++;
  1142.       XtSetArg(al[ac], XmNorientation, XmHORIZONTAL); ac++;
  1143.       XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_WIDGET); ac++;
  1144.       XtSetArg(al[ac], XmNbottomOffset, 13); ac++;
  1145.       XtSetArg(al[ac], XmNbottomWidget, separator); ac++;
  1146.       XtSetArg(al[ac], XmNleftAttachment, XmATTACH_WIDGET); ac++;
  1147.       XtSetArg(al[ac], XmNleftOffset, 13); ac++;
  1148.       XtSetArg(al[ac], XmNleftWidget, icon); ac++;
  1149.       XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
  1150.       XtSetArg(al[ac], XmNrightOffset, 13); ac++;
  1151.       value = XmCreateRadioBox (form, "radiobutton1", al, ac);
  1152.       ac = 0;
  1153.       i = 0;
  1154.       radio_butt = XmCreateToggleButtonGadget (value, "radio1", al, ac);
  1155.       children [i++] = radio_butt;
  1156.       radio_butt = XmCreateToggleButtonGadget (value, "radio2", al, ac);
  1157.       children [i++] = radio_butt;
  1158.       radio_butt = XmCreateToggleButtonGadget (value, "radio3", al, ac);
  1159.       children [i++] = radio_butt;
  1160.       XtManageChildren (children, i);
  1161.     }
  1162.   else if (list)
  1163.     {
  1164.       ac = 0;
  1165.       XtSetArg(al[ac], XmNvisibleItemCount, 5); ac++;
  1166.       XtSetArg(al[ac], XmNtopAttachment, XmATTACH_NONE); ac++;
  1167.       XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_WIDGET); ac++;
  1168.       XtSetArg(al[ac], XmNbottomOffset, 13); ac++;
  1169.       XtSetArg(al[ac], XmNbottomWidget, separator); ac++;
  1170.       XtSetArg(al[ac], XmNleftAttachment, XmATTACH_WIDGET); ac++;
  1171.       XtSetArg(al[ac], XmNleftOffset, 13); ac++;
  1172.       XtSetArg(al[ac], XmNleftWidget, icon); ac++;
  1173.       XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
  1174.       XtSetArg(al[ac], XmNrightOffset, 13); ac++;
  1175.       value = XmCreateScrolledList (form, "list", al, ac);
  1176.  
  1177.       /* this is the easiest way I found to have the dble click in the
  1178.      list activate the default button */
  1179.       XtAddCallback (value, XmNdefaultActionCallback, activate_button, button);
  1180.     }
  1181.   
  1182.   ac = 0;
  1183.   XtSetArg(al[ac], XmNalignment, XmALIGNMENT_BEGINNING); ac++;
  1184.   XtSetArg(al[ac], XmNtopAttachment, XmATTACH_FORM); ac++;
  1185.   XtSetArg(al[ac], XmNtopOffset, 13); ac++;
  1186.   XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_WIDGET); ac++;
  1187.   XtSetArg(al[ac], XmNbottomOffset, 13); ac++;
  1188.   XtSetArg(al[ac], XmNbottomWidget,
  1189.        text_input_slot || radio_box || list ? value : separator); ac++;
  1190.   XtSetArg(al[ac], XmNleftAttachment, XmATTACH_WIDGET); ac++;
  1191.   XtSetArg(al[ac], XmNleftOffset, 13); ac++;
  1192.   XtSetArg(al[ac], XmNleftWidget, icon); ac++;
  1193.   XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
  1194.   XtSetArg(al[ac], XmNrightOffset, 13); ac++;
  1195.   message = XmCreateLabel (form, "message", al, ac);
  1196.   DO_DND_KLUDGE (message);
  1197.   
  1198.   if (list)
  1199.     XtManageChild (value);
  1200.  
  1201.   i = 0;
  1202.   children [i] = row; i++;
  1203.   children [i] = separator; i++;
  1204.   if (text_input_slot || radio_box)
  1205.     {
  1206.       children [i] = value; i++;
  1207.     }
  1208.   children [i] = message; i++;
  1209.   children [i] = icon; i++;
  1210.   children [i] = icon_separator; i++;
  1211.   XtManageChildren (children, i);
  1212.   
  1213.   if (text_input_slot || list)
  1214.     {
  1215.       XtInstallAccelerators (value, button);
  1216.       XmProcessTraversal(value, XmTRAVERSE_CURRENT);
  1217.     }
  1218.   else
  1219.     {
  1220.       XtInstallAccelerators (form, button);
  1221.       XmProcessTraversal(value, XmTRAVERSE_CURRENT);
  1222.     }
  1223.   
  1224. #ifdef DND_KLUDGE
  1225.   XtFree ((char *) dnd_override);
  1226. #endif
  1227. #undef DO_DND_KLUDGE
  1228.  
  1229.   return result;
  1230. }
  1231.  
  1232. static destroyed_instance*
  1233. find_matching_instance (widget_instance* instance)
  1234. {
  1235.   destroyed_instance*    cur;
  1236.   destroyed_instance*    prev;
  1237.   char*    type = instance->info->type;
  1238.   char*    name = instance->info->name;
  1239.  
  1240.   for (prev = NULL, cur = all_destroyed_instances;
  1241.        cur;
  1242.        prev = cur, cur = cur->next)
  1243.     {
  1244.       if (!strcmp (cur->name, name)
  1245.       && !strcmp (cur->type, type)
  1246.       && cur->parent == instance->parent
  1247.       && cur->pop_up_p == instance->pop_up_p)
  1248.     {
  1249.       if (prev)
  1250.         prev->next = cur->next;
  1251.       else
  1252.         all_destroyed_instances = cur->next;
  1253.       return cur;
  1254.     }
  1255.       /* do some cleanup */
  1256.       else if (!cur->widget)
  1257.     {
  1258.       if (prev)
  1259.         prev->next = cur->next;
  1260.       else
  1261.         all_destroyed_instances = cur->next;
  1262.       free_destroyed_instance (cur);
  1263.       cur = prev ? prev : all_destroyed_instances;
  1264.     }
  1265.     }
  1266.   return NULL;
  1267. }
  1268.  
  1269. static void
  1270. mark_dead_instance_destroyed (Widget widget, XtPointer closure,
  1271.                   XtPointer call_data)
  1272. {
  1273.   destroyed_instance* instance = (destroyed_instance*)closure;
  1274.   instance->widget = NULL;
  1275. }
  1276.  
  1277. static void
  1278. recenter_widget (Widget widget)
  1279. {
  1280.   Widget parent = XtParent (widget);
  1281.   Screen* screen = XtScreen (widget);
  1282.   Dimension screen_width = WidthOfScreen (screen);
  1283.   Dimension screen_height = HeightOfScreen (screen);
  1284.   Dimension parent_width = 0;
  1285.   Dimension parent_height = 0;
  1286.   Dimension child_width = 0;
  1287.   Dimension child_height = 0;
  1288.   Position x;
  1289.   Position y;
  1290.  
  1291.   XtVaGetValues (widget, XtNwidth, &child_width, XtNheight, &child_height, 0);
  1292.   XtVaGetValues (parent, XtNwidth, &parent_width, XtNheight, &parent_height,
  1293.          0);
  1294.  
  1295.   x = (((Position)parent_width) - ((Position)child_width)) / 2;
  1296.   y = (((Position)parent_height) - ((Position)child_height)) / 2;
  1297.   
  1298.   XtTranslateCoords (parent, x, y, &x, &y);
  1299.  
  1300.   if ((Dimension) (x + child_width) > screen_width)
  1301.     x = screen_width - child_width;
  1302.   if (x < 0)
  1303.     x = 0;
  1304.  
  1305.   if ((Dimension) (y + child_height) > screen_height)
  1306.     y = screen_height - child_height;
  1307.   if (y < 0)
  1308.     y = 0;
  1309.  
  1310.   XtVaSetValues (widget, XtNx, x, XtNy, y, 0);
  1311. }
  1312.  
  1313. static Widget
  1314. recycle_instance (destroyed_instance* instance)
  1315. {
  1316.   Widget widget = instance->widget;
  1317.  
  1318.   /* widget is NULL if the parent was destroyed. */
  1319.   if (widget)
  1320.     {
  1321.       Widget focus;
  1322.       Widget separator;
  1323.  
  1324.       /* Remove the destroy callback as the instance is not in the list
  1325.      anymore */
  1326.       XtRemoveCallback (instance->parent, XtNdestroyCallback,
  1327.             mark_dead_instance_destroyed,
  1328.             (XtPointer)instance);
  1329.  
  1330.       /* Give the focus to the initial item */
  1331.       focus = XtNameToWidget (widget, "*value");
  1332.       if (!focus)
  1333.     focus = XtNameToWidget (widget, "*button1");
  1334.       if (focus)
  1335.     XmProcessTraversal(focus, XmTRAVERSE_CURRENT);
  1336.  
  1337.       /* shrink the separator label back to their original size */
  1338.       separator = XtNameToWidget (widget, "*separator_button");
  1339.       if (separator)
  1340.     XtVaSetValues (separator, XtNwidth, 5, XtNheight, 5, 0);
  1341.  
  1342.       /* Center the dialog in its parent */
  1343.       recenter_widget (widget);
  1344.     }
  1345.   free_destroyed_instance (instance);
  1346.   return widget;
  1347. }
  1348.  
  1349. Widget
  1350. xm_create_dialog (widget_instance* instance)
  1351. {
  1352.   char*     name = instance->info->type;
  1353.   Widget     parent = instance->parent;
  1354.   Widget    widget;
  1355.   Boolean     pop_up_p = instance->pop_up_p;
  1356.   char*        shell_name = 0;
  1357.   char*     icon_name = 0;
  1358.   Boolean    text_input_slot = False;
  1359.   Boolean    radio_box = False;
  1360.   Boolean    list = False;
  1361.   int        total_buttons;
  1362.   int        left_buttons = 0;
  1363.   int        right_buttons = 1;
  1364.   destroyed_instance*    dead_one;
  1365.  
  1366.   /* try to find a widget to recycle */
  1367.   dead_one = find_matching_instance (instance);
  1368.   if (dead_one)
  1369.     {
  1370.       Widget recycled_widget = recycle_instance (dead_one);
  1371.       if (recycled_widget)
  1372.     return recycled_widget;
  1373.     }
  1374.  
  1375.   switch (name [0]){
  1376.   case 'E': case 'e':
  1377.     icon_name = "dbox-error";
  1378.     shell_name = "Error";
  1379.     break;
  1380.  
  1381.   case 'I': case 'i':
  1382.     icon_name = "dbox-info";
  1383.     shell_name = "Information";
  1384.     break;
  1385.  
  1386.   case 'L': case 'l':
  1387.     list = True;
  1388.     icon_name = "dbox-question";
  1389.     shell_name = "Prompt";
  1390.     break;
  1391.  
  1392.   case 'P': case 'p':
  1393.     text_input_slot = True;
  1394.     icon_name = "dbox-question";
  1395.     shell_name = "Prompt";
  1396.     break;
  1397.  
  1398.   case 'Q': case 'q':
  1399.     icon_name = "dbox-question";
  1400.     shell_name = "Question";
  1401.     break;
  1402.   }
  1403.   
  1404.   total_buttons = name [1] - '0';
  1405.  
  1406.   if (name [3] == 'T' || name [3] == 't')
  1407.     {
  1408.       text_input_slot = False;
  1409.       radio_box = True;
  1410.     }
  1411.   else if (name [3])
  1412.     right_buttons = name [4] - '0';
  1413.   
  1414.   left_buttons = total_buttons - right_buttons;
  1415.   
  1416.   widget = make_dialog (name, parent, pop_up_p,
  1417.             shell_name, icon_name, text_input_slot, radio_box,
  1418.             list, left_buttons, right_buttons);
  1419.  
  1420.   XtAddCallback (widget, XmNpopdownCallback, xm_nosel_callback,
  1421.          (XtPointer) instance);
  1422.   return widget;
  1423. }
  1424.  
  1425. #ifdef MENUBARS_MOTIF
  1426. static Widget
  1427. make_menubar (widget_instance* instance)
  1428. {
  1429.   Arg al[10];
  1430.   int ac = 0;
  1431.  
  1432.   XtSetArg(al[ac], XmNmarginHeight, 0); ac++;
  1433.   XtSetArg(al[ac], XmNshadowThickness, 3); ac++;
  1434.  
  1435.   return XmCreateMenuBar (instance->parent, instance->info->name, al, ac);
  1436. }
  1437.  
  1438. static void
  1439. remove_grabs (Widget shell, XtPointer closure, XtPointer call_data)
  1440. {
  1441.   Widget menu = (Widget) closure;
  1442.   XmRemoveFromPostFromList (menu, XtParent (XtParent ((Widget) menu)));
  1443. }
  1444.  
  1445. static Widget
  1446. make_popup_menu (widget_instance* instance)
  1447. {
  1448.   Widget parent = instance->parent;
  1449.   Window parent_window = parent->core.window;
  1450.   Widget result;
  1451.  
  1452.   /* sets the parent window to 0 to fool Motif into not generating a grab */
  1453.   parent->core.window = 0;
  1454.   result = XmCreatePopupMenu (parent, instance->info->name, NULL, 0);
  1455.   XtAddCallback (XtParent (result), XmNpopdownCallback, remove_grabs,
  1456.          (XtPointer)result);
  1457.   parent->core.window = parent_window;
  1458.   return result;
  1459. }
  1460. #endif /* MENUBARS_MOTIF */
  1461.  
  1462. #ifdef SCROLLBARS_MOTIF
  1463. static Widget
  1464. make_scrollbar (widget_instance *instance, int vertical)
  1465. {
  1466.   Arg al[20];
  1467.   int ac = 0;
  1468.   Widget scrollbar;
  1469.  
  1470.   XtSetArg (al[ac], XmNminimum, 1); ac++;
  1471.   XtSetArg (al[ac], XmNmaximum, INT_MAX); ac++;
  1472.   XtSetArg (al[ac], XmNincrement, 1); ac++;
  1473.   XtSetArg (al[ac], XmNpageIncrement, 1); ac++;
  1474.   XtSetArg (al[ac], XmNborderWidth, 0); ac++;
  1475.   if (vertical)
  1476.     {
  1477.       XtSetArg (al[ac], XmNorientation, XmVERTICAL); ac++;
  1478.     }
  1479.   else
  1480.     {
  1481.       XtSetArg (al[ac], XmNorientation, XmHORIZONTAL); ac++;
  1482.     }
  1483.  
  1484.   scrollbar =
  1485.     XmCreateScrollBar (instance->parent, instance->info->name, al, ac);
  1486.  
  1487.   XtRemoveAllCallbacks (scrollbar, XmNdecrementCallback);
  1488.   XtRemoveAllCallbacks (scrollbar, XmNdragCallback);
  1489.   XtRemoveAllCallbacks (scrollbar, XmNincrementCallback);
  1490.   XtRemoveAllCallbacks (scrollbar, XmNpageDecrementCallback);
  1491.   XtRemoveAllCallbacks (scrollbar, XmNpageIncrementCallback);
  1492.   XtRemoveAllCallbacks (scrollbar, XmNtoBottomCallback);
  1493.   XtRemoveAllCallbacks (scrollbar, XmNtoTopCallback);
  1494.   XtRemoveAllCallbacks (scrollbar, XmNvalueChangedCallback);
  1495.  
  1496.   XtAddCallback(scrollbar, XmNdecrementCallback, xm_scrollbar_callback,
  1497.         (XtPointer) instance);
  1498.   XtAddCallback(scrollbar, XmNdragCallback, xm_scrollbar_callback,
  1499.         (XtPointer) instance);
  1500.   XtAddCallback(scrollbar, XmNincrementCallback, xm_scrollbar_callback,
  1501.         (XtPointer) instance);
  1502.   XtAddCallback(scrollbar, XmNpageDecrementCallback, xm_scrollbar_callback,
  1503.         (XtPointer) instance);
  1504.   XtAddCallback(scrollbar, XmNpageIncrementCallback, xm_scrollbar_callback,
  1505.         (XtPointer) instance);
  1506.   XtAddCallback(scrollbar, XmNtoBottomCallback, xm_scrollbar_callback,
  1507.         (XtPointer) instance);
  1508.   XtAddCallback(scrollbar, XmNtoTopCallback, xm_scrollbar_callback,
  1509.         (XtPointer) instance);
  1510.   XtAddCallback(scrollbar, XmNvalueChangedCallback, xm_scrollbar_callback,
  1511.         (XtPointer) instance);
  1512.  
  1513.   return scrollbar;
  1514. }
  1515.  
  1516. static Widget
  1517. make_vertical_scrollbar (widget_instance *instance)
  1518. {
  1519.   return make_scrollbar (instance, 1);
  1520. }
  1521.  
  1522. static Widget
  1523. make_horizontal_scrollbar (widget_instance *instance)
  1524. {
  1525.   return make_scrollbar (instance, 0);
  1526. }
  1527.  
  1528. #endif /* SCROLLBARS_MOTIF */
  1529.  
  1530. /* Table of functions to create widgets */
  1531.  
  1532. #ifdef ENERGIZE
  1533.  
  1534. /* interface with the XDesigner generated functions */
  1535. typedef Widget (*widget_maker) (Widget);
  1536. extern Widget create_project_p_sheet (Widget parent);
  1537. extern Widget create_debugger_p_sheet (Widget parent);
  1538. extern Widget create_breaklist_p_sheet (Widget parent);
  1539. extern Widget create_le_browser_p_sheet (Widget parent);
  1540. extern Widget create_class_browser_p_sheet (Widget parent);
  1541. extern Widget create_call_browser_p_sheet (Widget parent);
  1542. extern Widget create_build_dialog (Widget parent);
  1543. extern Widget create_editmode_dialog (Widget parent);
  1544. extern Widget create_search_dialog (Widget parent);
  1545. extern Widget create_project_display_dialog (Widget parent);
  1546.  
  1547. static Widget
  1548. make_one (widget_instance* instance, widget_maker fn)
  1549. {
  1550.   Widget result;
  1551.   Arg     al [64];
  1552.   int     ac = 0;
  1553.  
  1554.   if (instance->pop_up_p)
  1555.     {
  1556.       XtSetArg (al [ac], XmNallowShellResize, TRUE); ac++;
  1557.       result = XmCreateDialogShell (instance->parent, "dialog", NULL, 0);
  1558.       XtAddCallback (result, XmNpopdownCallback, &xm_nosel_callback,
  1559.              (XtPointer) instance);
  1560.       (*fn) (result);
  1561.     }
  1562.   else
  1563.     {
  1564.       result = (*fn) (instance->parent);
  1565.       XtRealizeWidget (result);
  1566.     }
  1567.   return result;
  1568. }
  1569.  
  1570. static Widget
  1571. make_project_p_sheet (widget_instance* instance)
  1572. {
  1573.   return make_one (instance, create_project_p_sheet);
  1574. }
  1575.  
  1576. static Widget
  1577. make_debugger_p_sheet (widget_instance* instance)
  1578. {
  1579.   return make_one (instance, create_debugger_p_sheet);
  1580. }
  1581.  
  1582. static Widget
  1583. make_breaklist_p_sheet (widget_instance* instance)
  1584. {
  1585.   return make_one (instance, create_breaklist_p_sheet);
  1586. }
  1587.  
  1588. static Widget
  1589. make_le_browser_p_sheet (widget_instance* instance)
  1590. {
  1591.   return make_one (instance, create_le_browser_p_sheet);
  1592. }
  1593.  
  1594. static Widget
  1595. make_class_browser_p_sheet (widget_instance* instance)
  1596. {
  1597.   return make_one (instance, create_class_browser_p_sheet);
  1598. }
  1599.  
  1600. static Widget
  1601. make_call_browser_p_sheet (widget_instance* instance)
  1602. {
  1603.   return make_one (instance, create_call_browser_p_sheet);
  1604. }
  1605.  
  1606. static Widget
  1607. make_build_dialog (widget_instance* instance)
  1608. {
  1609.   return make_one (instance, create_build_dialog);
  1610. }
  1611.  
  1612. static Widget
  1613. make_editmode_dialog (widget_instance* instance)
  1614. {
  1615.   return make_one (instance, create_editmode_dialog);
  1616. }
  1617.  
  1618. static Widget
  1619. make_search_dialog (widget_instance* instance)
  1620. {
  1621.   return make_one (instance, create_search_dialog);
  1622. }
  1623.  
  1624. static Widget
  1625. make_project_display_dialog (widget_instance* instance)
  1626. {
  1627.   return make_one (instance, create_project_display_dialog);
  1628. }
  1629.  
  1630. #endif /* ENERGIZE */
  1631.  
  1632. widget_creation_entry
  1633. xm_creation_table [] = 
  1634. {
  1635. #ifdef MENUBARS_MOTIF
  1636.   {"menubar",             make_menubar},
  1637.   {"popup",            make_popup_menu},
  1638. #endif
  1639. #ifdef SCROLLBARS_MOTIF
  1640.   {"vertical-scrollbar",    make_vertical_scrollbar},
  1641.   {"horizontal-scrollbar",    make_horizontal_scrollbar},
  1642. #endif
  1643. #ifdef ENERGIZE
  1644.   {"project_p_sheet",        make_project_p_sheet},
  1645.   {"debugger_p_sheet",        make_debugger_p_sheet},
  1646.   {"breaklist_psheet",        make_breaklist_p_sheet},
  1647.   {"leb_psheet",               make_le_browser_p_sheet},
  1648.   {"class_browser_psheet",    make_class_browser_p_sheet},
  1649.   {"ctree_browser_psheet",    make_call_browser_p_sheet},
  1650.   {"build",            make_build_dialog},
  1651.   {"editmode",            make_editmode_dialog},
  1652.   {"search",            make_search_dialog},
  1653.   {"project_display",        make_project_display_dialog},
  1654. #endif /* ENERGIZE */
  1655.   {NULL, NULL}
  1656. };
  1657.  
  1658. /* Destruction of instances */
  1659. void
  1660. xm_destroy_instance (widget_instance* instance)
  1661. {
  1662.   Widget widget = instance->widget;
  1663.   /* recycle the dialog boxes */
  1664.   /* Disable the recycling until we can find a way to have the dialog box
  1665.      get reasonable layout after we modify its contents. */
  1666.   if (0
  1667.       && XtClass (widget) == xmDialogShellWidgetClass)
  1668.     {
  1669.       destroyed_instance* dead_instance =
  1670.     make_destroyed_instance (instance->info->name,
  1671.                  instance->info->type,
  1672.                  instance->widget,
  1673.                  instance->parent,
  1674.                  instance->pop_up_p);
  1675.       dead_instance->next = all_destroyed_instances;
  1676.       all_destroyed_instances = dead_instance;
  1677.       XtUnmanageChild (first_child (instance->widget));
  1678.       XFlush (XtDisplay (instance->widget));
  1679.       XtAddCallback (instance->parent, XtNdestroyCallback,
  1680.              mark_dead_instance_destroyed, (XtPointer)dead_instance);
  1681.     }
  1682.   else
  1683.     {
  1684.       /* This might not be necessary now that the nosel is attached to
  1685.      popdown instead of destroy, but it can't hurt. */
  1686.       XtRemoveCallback (instance->widget, XtNdestroyCallback,
  1687.             xm_nosel_callback, (XtPointer)instance);
  1688.  
  1689.       XtDestroyWidget (instance->widget);
  1690.     }
  1691. }
  1692.  
  1693. /* popup utility */
  1694. void
  1695. xm_popup_menu (Widget widget, XEvent *event)
  1696. {
  1697.   if (event->type == ButtonPress || event->type == ButtonRelease)
  1698.     {
  1699.       /* This is so totally ridiculous: there's NO WAY to tell Motif
  1700.      that *any* button can select a menu item.  Only one button
  1701.      can have that honor.
  1702.        */
  1703.       char *trans = 0;
  1704.       if      (event->xbutton.state & Button5Mask) trans = "<Btn5Down>";
  1705.       else if (event->xbutton.state & Button4Mask) trans = "<Btn4Down>";
  1706.       else if (event->xbutton.state & Button3Mask) trans = "<Btn3Down>";
  1707.       else if (event->xbutton.state & Button2Mask) trans = "<Btn2Down>";
  1708.       else if (event->xbutton.state & Button1Mask) trans = "<Btn1Down>";
  1709.       if (trans) XtVaSetValues (widget, XmNmenuPost, trans, 0);
  1710.       XmMenuPosition (widget, (XButtonPressedEvent *) event);
  1711.     }
  1712.   XtManageChild (widget);
  1713. }
  1714.  
  1715. static void
  1716. set_min_dialog_size (Widget w)
  1717. {
  1718.   short width;
  1719.   short height;
  1720.   XtVaGetValues (w, XmNwidth, &width, XmNheight, &height, 0);
  1721.   XtVaSetValues (w, XmNminWidth, width, XmNminHeight, height, 0);
  1722. }
  1723.  
  1724. void
  1725. xm_pop_instance (widget_instance* instance, Boolean up)
  1726. {
  1727.   Widget widget = instance->widget;
  1728.  
  1729.   if (XtClass (widget) == xmDialogShellWidgetClass)
  1730.     {
  1731.       Widget widget_to_manage = first_child (widget);
  1732.       if (up)
  1733.     {
  1734.       XtManageChild (widget_to_manage);
  1735.       set_min_dialog_size (widget);
  1736.       XmProcessTraversal(widget, XmTRAVERSE_CURRENT);
  1737.     }
  1738.       else
  1739.     XtUnmanageChild (widget_to_manage);
  1740.     }
  1741.   else
  1742.     {
  1743.       if (up)
  1744.     XtManageChild (widget);
  1745.       else
  1746.     XtUnmanageChild (widget);    
  1747.     }
  1748. }
  1749.  
  1750.  
  1751. /* motif callback */ 
  1752.  
  1753. enum do_call_type { pre_activate, selection, no_selection, post_activate };
  1754.  
  1755. static void
  1756. do_call (Widget widget, XtPointer closure, enum do_call_type type)
  1757. {
  1758.   XtPointer user_data;
  1759.   widget_instance* instance = (widget_instance*)closure;
  1760.   Widget instance_widget;
  1761.   LWLIB_ID id;
  1762.  
  1763.   if (!instance)
  1764.     return;
  1765.   if (widget->core.being_destroyed)
  1766.     return;
  1767.  
  1768.   instance_widget = instance->widget;
  1769.   if (!instance_widget)
  1770.     return;
  1771.  
  1772.   id = instance->info->id;
  1773.   user_data = NULL;
  1774.   XtVaGetValues (widget, XmNuserData, &user_data, NULL);
  1775.   switch (type)
  1776.     {
  1777.     case pre_activate:
  1778.       if (instance->info->pre_activate_cb)
  1779.     instance->info->pre_activate_cb (widget, id, user_data);
  1780.       break;
  1781.     case selection:
  1782.       if (instance->info->selection_cb)
  1783.     instance->info->selection_cb (widget, id, user_data);
  1784.       break;
  1785.     case no_selection:
  1786.       if (instance->info->selection_cb)
  1787.     instance->info->selection_cb (widget, id, (XtPointer) -1);
  1788.       break;
  1789.     case post_activate:
  1790.       if (instance->info->post_activate_cb)
  1791.     instance->info->post_activate_cb (widget, id, user_data);
  1792.       break;
  1793.     default:
  1794.       abort ();
  1795.     }
  1796. }
  1797.  
  1798. /* Like lw_internal_update_other_instances except that it does not do
  1799.    anything if its shell parent is not managed.  This is to protect 
  1800.    lw_internal_update_other_instances to dereference freed memory
  1801.    if the widget was ``destroyed'' by caching it in the all_destroyed_instances
  1802.    list */
  1803. static void
  1804. xm_internal_update_other_instances (Widget widget, XtPointer closure,
  1805.                     XtPointer call_data)
  1806. {
  1807.   Widget parent;
  1808.   for (parent = widget; parent; parent = XtParent (parent))
  1809.     if (XtIsShell (parent))
  1810.       break;
  1811.     else if (!XtIsManaged (parent))
  1812.       return;
  1813.    lw_internal_update_other_instances (widget, closure, call_data);
  1814. }
  1815.  
  1816. static void
  1817. xm_generic_callback (Widget widget, XtPointer closure, XtPointer call_data)
  1818. {
  1819. #ifndef ENERGIZE
  1820.   /* We want the selected status to change only when we decide it
  1821.      should change.  Yuck but correct. */
  1822.   if (XtClass (widget) == xmToggleButtonWidgetClass
  1823.       || XtClass (widget) == xmToggleButtonGadgetClass)
  1824.     {
  1825.       Boolean check;
  1826.       XtVaGetValues (widget, XmNset, &check, 0);
  1827.       XtVaSetValues (widget, XmNset, !check, 0);
  1828.     }
  1829. #endif 
  1830.   lw_internal_update_other_instances (widget, closure, call_data);
  1831.   do_call (widget, closure, selection);
  1832. }
  1833.  
  1834. static void
  1835. xm_nosel_callback (Widget widget, XtPointer closure, XtPointer call_data)
  1836. {
  1837.   /* This callback is only called when a dialog box is dismissed with the wm's
  1838.      destroy button (WM_DELETE_WINDOW.)  We want the dialog box to be destroyed
  1839.      in that case, not just unmapped, so that it releases its keyboard grabs.
  1840.      But there are problems with running our callbacks while the widget is in
  1841.      the process of being destroyed, so we set XmNdeleteResponse to XmUNMAP
  1842.      instead of XmDESTROY and then destroy it ourself after having run the
  1843.      callback.
  1844.    */
  1845.   do_call (widget, closure, no_selection);
  1846.   XtDestroyWidget (widget);
  1847. }
  1848.  
  1849. static void
  1850. xm_pull_down_callback (Widget widget, XtPointer closure, XtPointer call_data)
  1851. {
  1852. #if 0
  1853.   if (call_data)
  1854.     {
  1855.       /* new behavior for incremental menu construction */
  1856.       
  1857.     }
  1858.   else
  1859. #endif 
  1860.     do_call (widget, closure, pre_activate);
  1861. }
  1862.  
  1863. #if 0
  1864. static void
  1865. xm_pop_down_callback (Widget widget, XtPointer closure, XtPointer call_data)
  1866. {
  1867.   do_call (widget, closure, post_activate);
  1868. }
  1869. #endif /* 0 */
  1870.  
  1871. #ifdef SCROLLBARS_MOTIF
  1872. static void
  1873. xm_scrollbar_callback (Widget widget, XtPointer closure, XtPointer call_data)
  1874. {
  1875.   widget_instance *instance = (widget_instance *) closure;
  1876.   LWLIB_ID id;
  1877.   XmScrollBarCallbackStruct *data =
  1878.     (XmScrollBarCallbackStruct *) call_data;
  1879.   scroll_event event_data;
  1880.   scrollbar_values *val =
  1881.     (scrollbar_values *) instance->info->val->scrollbar_data;
  1882.   double percent;
  1883.  
  1884.   if (!instance || widget->core.being_destroyed)
  1885.     return;
  1886.  
  1887.   id = instance->info->id;
  1888.  
  1889.   percent = (double) (data->value - 1) / (double) (INT_MAX - 1);
  1890.   event_data.slider_value =
  1891.     (int) (percent * (double) (val->maximum - val->minimum)) + val->minimum;
  1892.  
  1893.   if (event_data.slider_value > (val->maximum - val->slider_size))
  1894.     event_data.slider_value = val->maximum - val->slider_size;
  1895.   else if (event_data.slider_value < 1)
  1896.     event_data.slider_value = 1;
  1897.  
  1898.   if (data->event)
  1899.     {
  1900.       switch (data->event->xany.type)
  1901.     {
  1902.     case KeyPress:
  1903.     case KeyRelease:
  1904.       event_data.time = data->event->xkey.time;
  1905.       break;
  1906.     case ButtonPress:
  1907.     case ButtonRelease:
  1908.       event_data.time = data->event->xbutton.time;
  1909.       break;
  1910.     case MotionNotify:
  1911.       event_data.time = data->event->xmotion.time;
  1912.       break;
  1913.     case EnterNotify:
  1914.     case LeaveNotify:
  1915.       event_data.time = data->event->xcrossing.time;
  1916.       break;
  1917.     default:
  1918.       event_data.time = 0;
  1919.       break;
  1920.     }
  1921.     }
  1922.   else
  1923.     event_data.time = 0;
  1924.  
  1925.   switch (data->reason)
  1926.     {
  1927.     case XmCR_DECREMENT:
  1928.       event_data.action = SCROLLBAR_LINE_UP;
  1929.       break;
  1930.     case XmCR_INCREMENT:
  1931.       event_data.action = SCROLLBAR_LINE_DOWN;
  1932.       break;
  1933.     case XmCR_PAGE_DECREMENT:
  1934.       event_data.action = SCROLLBAR_PAGE_UP;
  1935.       break;
  1936.     case XmCR_PAGE_INCREMENT:
  1937.       event_data.action = SCROLLBAR_PAGE_DOWN;
  1938.       break;
  1939.     case XmCR_TO_TOP:
  1940.       event_data.action = SCROLLBAR_TOP;
  1941.       break;
  1942.     case XmCR_TO_BOTTOM:
  1943.       event_data.action = SCROLLBAR_BOTTOM;
  1944.       break;
  1945.     case XmCR_DRAG:
  1946.       event_data.action = SCROLLBAR_DRAG;
  1947.       break;
  1948.     case XmCR_VALUE_CHANGED:
  1949.       event_data.action = SCROLLBAR_CHANGE;
  1950.       break;
  1951.     default:
  1952.       event_data.action = SCROLLBAR_CHANGE;
  1953.       break;
  1954.     }
  1955.  
  1956.   if (instance->info->pre_activate_cb)
  1957.     instance->info->pre_activate_cb (widget, id, (XtPointer) &event_data);
  1958. }
  1959. #endif
  1960.  
  1961.  
  1962. /* set the keyboard focus */
  1963. void
  1964. xm_set_keyboard_focus (Widget parent, Widget w)
  1965. {
  1966.   XmProcessTraversal (w, XmTRAVERSE_CURRENT);
  1967.   /* At some point we believed that it was necessary to use XtSetKeyboardFocus
  1968.      instead of XmProcessTraversal when using Motif >= 1.2.1, but that's bogus.
  1969.      Presumably the problem was elsewhere, and is now gone...
  1970.    */
  1971. }
  1972.